/*    
 * THis file is part of the xoperator SPARQL/XMPP agent.
 * For further information see: http://xoperator.sf.net
 * Copyright (C) 2007  Jörg Unbehauen  

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */
package net.sf.xoperator.configuration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import net.sf.xoperator.blackboard.ConfigurationAwareKnowledgeSource;
import net.sf.xoperator.blackboard.NoPlanBlackBoardControl;
import net.sf.xoperator.ui.UIAimlConfiguration;
import net.sf.xoperator.ui.aiml.AIMLTemplate;
import net.sf.xoperator.xmpp.AccountInfo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openbbs.blackboard.filter.KindOfFilter;
import org.openbbs.blackboard.ks.KSExecutionContext;

public class SerializingPersonalDataStore extends
		ConfigurationAwareKnowledgeSource {
	

	private NoPlanBlackBoardControl control;

	private Map<String, KSConfiguration> configs = new ConcurrentHashMap<String, KSConfiguration>();
			

	private Log log = LogFactory.getLog(SerializingPersonalDataStore.class);

	private SerialisingPersister persist = null;

	public SerializingPersonalDataStore(NoPlanBlackBoardControl control) {
		super();
		this.control = control;
	}

	@Override
	public List<Class<? extends KSConfiguration>> getConfigurationClasses() {
		List<Class<? extends KSConfiguration>> classes = new ArrayList<Class<? extends KSConfiguration>>();
		classes.add(KSConfiguration.class);
		return classes;
	}

	/**
	 * the configuration information of the agent is assembled here. at least
	 * the username of the of the main account as to be set for laoding the
	 * prviously stored data.
	 * 
	 * @param main
	 * @param proxy
	 */
	public void initialize(AccountInfo main, AccountInfo proxy) {
		this.persist = new SerialisingPersister(main.getUsername());
		this.log.info("Using folder: " + this.persist.getUserFolder().getAbsolutePath());
		
		Map<String, KSConfiguration> configs = this.persist.loadConfiguration(main, proxy);
		
		if(configs==null){
		 

			configs = this.persist.createUserFolder(main, proxy);

			
		}

		for (KSConfiguration conf : configs.values()) {
			this.control.getConfigurationContext().blackboard().write(conf);
			this.control.propagateConfiguration(conf);
		}

	}

		

	@Override
	public void configure(KSConfiguration config) throws Exception {
		boolean changed = false;
		//should it be delted or not
		if (!config.isObsolete()) {
			//is the config a new, i.e. nonexitent in the map? 
			if (this.configs.get(keyForConf(config)) == null){
				this.configs.put(keyForConf(config), config);
				changed = true;
				
			}else if(!this.configs.get(keyForConf(config)).equals(config)) { // check if it just a copy, when it is, do nothing
				this.configs.put(keyForConf(config), config);
				changed = true;
			}

		} else {
			this.configs.remove(config.getClass().getCanonicalName()
					+ config.getName());
			changed = true;
		}
		if (changed) {
			this.control.getConfigurationContext().blackboard().write(config);
			this.saveConfigs();
		}

	}

	@Override
	public void executeInternal(KSExecutionContext context) {
		// Do nothing here, everything is done by the configure method

	}

	@Override
	public boolean isEnabledInternal(KSExecutionContext context) {
		return false;
	}
	
	private String keyForConf(KSConfiguration conf){
		return conf.getClass().getCanonicalName()
		+ conf.getName();
	}
	
	/**
	 * dispatches the KSConfiguration to its persisting methods
	 *
	 */
	private void saveConfigs(){
//		as we only want to save the PersistantConfigurations
		Map<String, PersistentKSConfiguration> persistanconfs = new HashMap<String, PersistentKSConfiguration>();
		Map<String, AIMLTemplate> aimlconf = new HashMap<String, AIMLTemplate>();
		for (String key : configs.keySet()) {
			if(configs.get(key) instanceof PersistentKSConfiguration){
				persistanconfs.put(key, (PersistentKSConfiguration) configs.get(key));
			}
			if (configs.get(key) instanceof AIMLTemplate){
				aimlconf.put(key, (AIMLTemplate) configs.get(key));
			}
		}
	
		this.persist.saveConfiguration(persistanconfs);
		if(this.persist.saveAimlConfig(aimlconf)){
			//we need to reset the aiml engine
			control.propagateConfiguration((KSConfiguration) control.getConfigurationContext().blackboard().read(new KindOfFilter(UIAimlConfiguration.class)));
		}
	}

	
}
